import React, { PureComponent } from 'react'
import { TransitionGroup, CSSTransition } from 'react-transition-group'
import { Switch, withRouter } from 'react-router-dom'
import {findDOMNode} from 'react-dom'
import propTypes from 'prop-types'

const HISTORIES_KEY = '__HISTORIES_KEY__'
const histories = (sessionStorage.getItem(HISTORIES_KEY) || '').split(',').filter(Boolean)

let lastLocation = { isPush: true }
const isHistoryPush = (location, update) => {
  const key = location.key || location.pathname + location.search;
  if (update && key !== lastLocation.key) {
    const index = histories.lastIndexOf(key)

    if (index > -1) {
      histories.splice(index + 1)
    } else {
      histories.push(key)
    }

    sessionStorage.setItem(HISTORIES_KEY, histories.join(','))

    lastLocation = {
      isPush: index < 0,
      key
    }
  }
  return lastLocation.isPush
}

@withRouter
class AnimatedRouter extends PureComponent {
  inTransition = false
  componentDidMount() {
    this.rootDom = findDOMNode(this)
  }
  componentWillReceiveProps() {
    this.lastHistoryPath = this.props.location.pathname
  }
  setTransition = (isAdd) => {
    if (this.rootDom) {
      const inName = 'router-in-transition'
      this.rootDom.className = this.rootDom.className
        .split(/\s+/)
        .filter(name => name !== inName)
        .concat(isAdd ? inName : [])
        .join(' ')
    }
  }
  onEnter = node => {
    this.inTransition || this.setTransition((this.inTransition = true))
  }
  onEntered = node => {
    this.inTransition && this.setTransition((this.inTransition = false))
  }
  render() {
    const { className, location, children, transition, fade } = this.props
    if (!transition) return (
      <Switch location={location}>{children}</Switch>
    )
    return (
      <TransitionGroup
        className={'page-animation-container' + (className ? ' ' + className : '')}
        childFactory={child => {
          let classNames = isHistoryPush(location, child.props.in) ? 'forward' : 'backward'
          const routeName = location.pathname
          if (fade(routeName, this.lastHistoryPath)) classNames = 'fade'
          return React.cloneElement(child, {
            classNames
          })
        }}>
        <CSSTransition
          key={this.props.transitionKey || location.pathname}
          onExit={this.onEnter}
          onExited={this.onEntered}
          onEnter={this.onEnter}
          onEntered={this.onEntered}
          enter={true}
          exit={true}
          addEndListener={(node, done) => {
            node.addEventListener(
              'transitionend',
              function(e) {
                // 确保动画来自于目标节点
                if (e.target === node) {
                  done()
                }
              },
              false
            )
          }}
          timeout={300}>
          <div style={{
            height: '100%',
            width: '100%'
          }}>
            <Switch location={location}>{children}</Switch>
          </div>
        </CSSTransition>
      </TransitionGroup>
    )
  }
}

AnimatedRouter.propTypes = {
  transitionKey: propTypes.string,
  transition: propTypes.bool,
  fade: propTypes.func
}

AnimatedRouter.defaultProps = {
  transition: true,
  fade: []
}

export default AnimatedRouter
